package com.ssy.lingxi.member.merchant.serviceimpl.base;

import com.ssy.lingxi.common.constant.basic.EnableDisableStatus;
import com.ssy.lingxi.common.constant.member.MemberStatusEnum;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.utils.DateTimeUtil;
import com.ssy.lingxi.member.merchant.api.constant.MemberCreditTypeEnum;
import com.ssy.lingxi.member.merchant.config.ServiceConfig;
import com.ssy.lingxi.member.merchant.entity.BaseCreditConfigDO;
import com.ssy.lingxi.member.merchant.entity.MemberAfterSaleHistoryDO;
import com.ssy.lingxi.member.merchant.entity.MemberCreditDO;
import com.ssy.lingxi.member.merchant.entity.MemberRelationDO;
import com.ssy.lingxi.member.merchant.api.constant.MemberRelationTypeEnum;
import com.ssy.lingxi.member.merchant.model.constant.MemberValidateStatusEnum;
import com.ssy.lingxi.member.merchant.repository.BaseCreditConfigRepository;
import com.ssy.lingxi.member.merchant.repository.MemberAfterSaleHistoryRepository;
import com.ssy.lingxi.member.merchant.repository.MemberCreditRepository;
import com.ssy.lingxi.member.merchant.repository.MemberRelationRepository;
import com.ssy.lingxi.member.merchant.service.base.IBaseMemberCreditAsyncService;
import com.ssy.lingxi.member.merchant.service.base.IBaseMemberLrcCacheService;
import com.ssy.lingxi.member.merchant.service.feign.IPlatformTemplateFeignService;
import com.ssy.lingxi.member.merchant.service.feign.IProductFeignService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

/**
 * 会员信用相关计算异步接口实现类
 * @author 万宁
 * @version 2.0.0
 * @date 2020-11-18
 */
@Service
public class BaseMemberCreditAsyncServiceImpl implements IBaseMemberCreditAsyncService {
    private static final Logger logger = LoggerFactory.getLogger(BaseMemberCreditAsyncServiceImpl.class);

    @Resource
    private IBaseMemberLrcCacheService lrcCacheService;

    @Resource
    private MemberRelationRepository relationRepository;

    @Resource
    private BaseCreditConfigRepository baseCreditConfigRepository;

    @Resource
    private MemberCreditRepository memberCreditRepository;

    @Resource
    private MemberAfterSaleHistoryRepository memberAfterSaleHistoryRepository;

    @Resource
    private IProductFeignService productFeignService;

    @Resource
    private IPlatformTemplateFeignService templateFeignService;

    /**
     * 计算会员交易评价信用积分
     * @param upperMemberId 上级会员Id（评价发起方）
     * @param upperRoleId   上级会员角色Id
     * @param subMemberId   下级会员Id  （被评论方）
     * @param subRoleId     下级会员角色Id
     * @param commentStar 评论星级
     */
    @Async
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public void calculateMemberTradeCommentCredit(Long upperMemberId, Long upperRoleId, Long subMemberId, Long subRoleId, Integer commentStar) {
        //Step 1: 查询会员关系，如果存在则计算会员信用
        MemberRelationDO relationDO = relationRepository.findFirstByMemberIdAndRoleIdAndSubMemberIdAndSubRoleId(upperMemberId, upperRoleId, subMemberId, subRoleId);
        if (relationDO != null && relationDO.getVerified().equals(MemberValidateStatusEnum.VERIFY_PASSED.getCode()) && relationDO.getStatus().equals(MemberStatusEnum.NORMAL.getCode()) && !calculateMemberCredit(relationDO, MemberCreditTypeEnum.BY_TRADE_COMMENT_FIVE_STARS, commentStar)) {
            return;
        }

        //Step 2: 查询被评论方的平台关系，计算平台信用积分
        MemberRelationDO platformMemberRelationDO = relationRepository.findFirstBySubMemberIdAndSubRoleIdAndRelType(subMemberId, subRoleId, MemberRelationTypeEnum.PLATFORM.getCode());
        if(platformMemberRelationDO == null) {
            logger.error(String.format("计算会员信用错误，会员Id:%d , 角色Id: %d 没有平台会员关系", subMemberId, subRoleId));
            return;
        }

        //平台会员为审核通过、未冻结时，才计算
        if(platformMemberRelationDO.getVerified().equals(MemberValidateStatusEnum.VERIFY_PASSED.getCode()) && platformMemberRelationDO.getStatus().equals(MemberStatusEnum.NORMAL.getCode())) {
            calculateMemberCredit(platformMemberRelationDO, MemberCreditTypeEnum.BY_TRADE_COMMENT_FIVE_STARS, commentStar);
        }

    }

    /**
     * 计算会员投诉信用积分
     *
     * @param upperMemberId 上级会员Id（投诉发起方）
     * @param upperRoleId   上级会员角色Id
     * @param subMemberId   下级会员Id  （被投诉方）
     * @param subRoleId     下级会员角色Id
     */
    @Async
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public void calculateMemberTradeComplainCredit(Long upperMemberId, Long upperRoleId, Long subMemberId, Long subRoleId) {
        //Step 1: 查询会员关系，如果存在则计算会员信用
        MemberRelationDO relationDO = relationRepository.findFirstByMemberIdAndRoleIdAndSubMemberIdAndSubRoleId(upperMemberId, upperRoleId, subMemberId, subRoleId);
        if (relationDO != null && relationDO.getVerified().equals(MemberValidateStatusEnum.VERIFY_PASSED.getCode()) && relationDO.getStatus().equals(MemberStatusEnum.NORMAL.getCode()) && !calculateMemberCredit(relationDO, MemberCreditTypeEnum.BY_COMPLAIN, 0)) {
            return;
        }

        //Step 2: 查询被评论方的平台关系，计算平台信用积分
        MemberRelationDO platformMemberRelationDO = relationRepository.findFirstBySubMemberIdAndSubRoleIdAndRelType(subMemberId, subRoleId, MemberRelationTypeEnum.PLATFORM.getCode());
        if(platformMemberRelationDO == null) {
            logger.error(String.format("计算会员信用错误，会员Id:%d , 角色Id: %d 没有平台会员关系", subMemberId, subRoleId));
            return;
        }

        if(platformMemberRelationDO.getVerified().equals(MemberValidateStatusEnum.VERIFY_PASSED.getCode()) && platformMemberRelationDO.getStatus().equals(MemberStatusEnum.NORMAL.getCode())) {
            calculateMemberCredit(platformMemberRelationDO, MemberCreditTypeEnum.BY_COMPLAIN, 0);
        }
    }

    /**
     * 计算会员售后评价信用积分
     * @param upperMemberId 上级会员Id（评论发起方）
     * @param upperRoleId 上级会员角色Id
     * @param subMemberId  下级会员Id  （被评论方）
     * @param subRoleId   下级会员角色Id
     * @param afterSaleTime 售后时间
     * @param star        评论星级
     * @param product     售后商品
     * @param comment      评论内容
     * @param orderNo     售后单号
     */
    @Async
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public void calculateMemberAfterSaleCommentCredit(Long upperMemberId, Long upperRoleId, Long subMemberId, Long subRoleId, String afterSaleTime, Integer star, String product, String comment, String orderNo) {
        //Step 1: 查询会员关系，如果存在则计算会员信用
        final Integer fiveStar = 5;
        MemberRelationDO relationDO = relationRepository.findFirstByMemberIdAndRoleIdAndSubMemberIdAndSubRoleId(upperMemberId, upperRoleId, subMemberId, subRoleId);
        if (relationDO != null && relationDO.getVerified().equals(MemberValidateStatusEnum.VERIFY_PASSED.getCode()) && relationDO.getStatus().equals(MemberStatusEnum.NORMAL.getCode())){
            if(star.equals(fiveStar) && !calculateMemberCredit(relationDO, MemberCreditTypeEnum.BY_COMMENT_AFTER_TRADE, star)) {
                return;
            }

            MemberAfterSaleHistoryDO historyDO = new MemberAfterSaleHistoryDO();
            historyDO.setCreateTime(LocalDateTime.now());
            historyDO.setAfterSaleTime(LocalDateTime.parse(afterSaleTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            historyDO.setMemberId(upperMemberId);
            historyDO.setRoleId(upperRoleId);
            historyDO.setSubMemberId(subMemberId);
            historyDO.setSubRoleId(subRoleId);
            historyDO.setRelType(relationDO.getRelType());
            historyDO.setMemberName(relationDO.getMember().getName());
            historyDO.setStar(star);
            historyDO.setComment(comment);
            historyDO.setProduct(product);
            historyDO.setRemark(orderNo);
            memberAfterSaleHistoryRepository.saveAndFlush(historyDO);
        }

        //Step 2: 查询被评论方的平台关系，计算平台信用积分
        MemberRelationDO platformMemberRelationDO = relationRepository.findFirstBySubMemberIdAndSubRoleIdAndRelType(subMemberId, subRoleId, MemberRelationTypeEnum.PLATFORM.getCode());
        if(platformMemberRelationDO == null) {
            logger.error(String.format("计算会员信用错误，会员Id:%d , 角色Id: %d 没有平台会员关系", subMemberId, subRoleId));
            return;
        }

        if(platformMemberRelationDO.getVerified().equals(MemberValidateStatusEnum.VERIFY_PASSED.getCode()) && platformMemberRelationDO.getStatus().equals(MemberStatusEnum.NORMAL.getCode())) {
            calculateMemberCredit(platformMemberRelationDO, MemberCreditTypeEnum.BY_COMMENT_AFTER_TRADE, star);
        }

    }

    /**
     * 计算会员（下级会员）注册年数信用积分
     * @param memberRelationDOList 下级会员的关系列表
     */
    @Async
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public void calculateMemberRegisterYearsCredit(List<MemberRelationDO> memberRelationDOList) {
        BaseCreditConfigDO baseCreditConfigDO = baseCreditConfigRepository.findFirstByCreditTypeEnum(MemberCreditTypeEnum.BY_REGISTER_YEARS.getCode());
        if (baseCreditConfigDO == null || baseCreditConfigDO.getCreditPoint().equals(0) || baseCreditConfigDO.getStatus().equals(EnableDisableStatus.DISABLE.getCode())) {
            return;
        }

        List<MemberCreditDO> creditDOList = new ArrayList<>();
        //查找所有关系
        for(MemberRelationDO relationDO : memberRelationDOList) {
            if(!relationDO.getVerified().equals(MemberValidateStatusEnum.VERIFY_PASSED.getCode())) {
                continue;
            }

            LocalDateTime registerTime = relationDO.getCreateTime();
            Integer registerYears = DateTimeUtil.diffYears(registerTime, LocalDateTime.now());
            if(registerYears <= 0) {
                continue;
            }

            LocalDateTime updateTime = relationDO.getCredit().getRegisterPointUpdateTime();
            Integer updateYears = DateTimeUtil.diffYears(updateTime, LocalDateTime.now());
            if(updateYears <= 0) {
                continue;
            }

            MemberCreditDO creditDO = relationDO.getCredit();
            if(creditDO == null) {
                logger.error("计算会员注册年限信用积分错误： 会员RelationId:" + relationDO.getId() + "没有当前权益数据");
                continue;
            }

//            int seed = registerYears - updateYears;
//            Integer plusPoint = seed > 0 ? seed * baseCreditConfigDO.getCreditPoint() : 0;

            int seed = updateYears;
            Integer plusPoint = seed * baseCreditConfigDO.getCreditPoint();
            if(plusPoint > 0) {
                creditDO.setCreditPoint(creditDO.getCreditPoint() + plusPoint);
                creditDO.setRegisterYearsPoint(creditDO.getRegisterYearsPoint() + plusPoint);
                creditDO.setRegisterPointUpdateTime(LocalDateTime.now());
                creditDOList.add(creditDO);

                //缓存
                if(relationDO.getRelType().equals(MemberRelationTypeEnum.PLATFORM.getCode())) {
                    if(creditDO.getTradeCommentCount().equals(0)) {
                        lrcCacheService.cacheMemberCredit(relationDO.getSubMemberId(), relationDO.getSubRoleId(), creditDO.getCreditPoint(), creditDO.getTradeCommentPoint(), creditDO.getAfterSaleCommentPoint(), creditDO.getComplainPoint(), creditDO.getRegisterYearsPoint(), ServiceConfig.DEFAULT_TRADE_COMMENT_STAR, registerYears);
                    } else {
                        lrcCacheService.cacheMemberCredit(relationDO.getSubMemberId(), relationDO.getSubRoleId(), creditDO.getCreditPoint(), creditDO.getTradeCommentPoint(), creditDO.getAfterSaleCommentPoint(), creditDO.getComplainPoint(), creditDO.getRegisterYearsPoint(), creditDO.getAvgTradeCommentStar(), registerYears);
                    }

                    //通知
                    productFeignService.updateCommodityCreditScoreAsync(relationDO.getSubMemberId(), relationDO.getSubRoleId(), relationDO.getSubRole().getMemberType().getTypeEnum(), plusPoint);

                    if(creditDO.getTradeCommentCount().equals(0)) {
                        templateFeignService.notifyCreditChangedAsync(relationDO.getSubMemberId(), relationDO.getSubRoleId(), relationDO.getSubMember().getName(), creditDO.getCreditPoint(), registerYears, ServiceConfig.DEFAULT_TRADE_COMMENT_STAR);
                    } else {
                        templateFeignService.notifyCreditChangedAsync(relationDO.getSubMemberId(), relationDO.getSubRoleId(), relationDO.getSubMember().getName(), creditDO.getCreditPoint(), registerYears, creditDO.getAvgTradeCommentStar());
                    }
                }
            }
        }

        if(!CollectionUtils.isEmpty(creditDOList)) {
            memberCreditRepository.saveAll(creditDOList);
        }

    }

    /**
     * 计算会员信用
     * @param relationDO 会员关系
     * @param memberCreditTypeEnum 信用类型枚举
     * @param commentStar 评论星级
     * @return 是否成功
     */
    private Boolean calculateMemberCredit(MemberRelationDO relationDO, MemberCreditTypeEnum memberCreditTypeEnum, Integer commentStar) {
        MemberCreditDO memberCreditDO = relationDO.getCredit();
        if(memberCreditDO == null) {
            logger.error("计算会员信用错误，会员关系Id:" + relationDO.getId() + " 没有信用信息");
            return false;
        }

        BaseCreditConfigDO baseCreditConfigDO = baseCreditConfigRepository.findFirstByCreditTypeEnum(memberCreditTypeEnum.getCode());
        if(baseCreditConfigDO == null || baseCreditConfigDO.getStatus().equals(EnableDisableStatus.DISABLE.getCode()) || baseCreditConfigDO.getCreditPoint().equals(0)) {
            return true;
        }

        Integer plusPoint = baseCreditConfigDO.getCreditPoint();
        switch (memberCreditTypeEnum) {
            //交易评论满5星
            case BY_TRADE_COMMENT_FIVE_STARS:
                final Integer fiveStar = 5;
                if(commentStar.equals(fiveStar)) {
                    memberCreditDO.setTradeCommentPoint(memberCreditDO.getTradeCommentPoint() + plusPoint);
                }
                memberCreditDO.setTradeCommentCount(memberCreditDO.getTradeCommentCount() + 1);
                memberCreditDO.setTradeCommentStars(memberCreditDO.getTradeCommentStars() + commentStar);
                float avgTradeCommentStar = memberCreditDO.getTradeCommentStars().floatValue() / memberCreditDO.getTradeCommentCount();
                memberCreditDO.setAvgTradeCommentStar(Math.round(avgTradeCommentStar));
                break;
            // 投诉
            case BY_COMPLAIN:
                memberCreditDO.setComplainPoint(memberCreditDO.getComplainPoint() + plusPoint);
                break;
            //售后评价
            case BY_COMMENT_AFTER_TRADE:
                memberCreditDO.setAfterSaleCommentPoint(memberCreditDO.getAfterSaleCommentPoint() + plusPoint);
                break;
            //注册年数
            case BY_REGISTER_YEARS:
                memberCreditDO.setRegisterYearsPoint(memberCreditDO.getRegisterYearsPoint() + plusPoint);
                memberCreditDO.setRegisterPointUpdateTime(LocalDateTime.now());
                break;
            default:
                break;
        }

        memberCreditDO.setCreditPoint(memberCreditDO.getTradeCommentPoint() + memberCreditDO.getComplainPoint() + memberCreditDO.getAfterSaleCommentPoint() + memberCreditDO.getRegisterYearsPoint());
        memberCreditRepository.saveAndFlush(memberCreditDO);

        //缓存
        if(relationDO.getRelType().equals(MemberRelationTypeEnum.PLATFORM.getCode())) {
            if(memberCreditDO.getTradeCommentCount().equals(0)) {
                lrcCacheService.cacheMemberCredit(relationDO.getSubMemberId(), relationDO.getSubRoleId(), memberCreditDO.getCreditPoint(), memberCreditDO.getTradeCommentPoint(), memberCreditDO.getAfterSaleCommentPoint(), memberCreditDO.getComplainPoint(), memberCreditDO.getRegisterYearsPoint(), ServiceConfig.DEFAULT_TRADE_COMMENT_STAR, DateTimeUtil.diffYears(relationDO.getCreateTime(), LocalDateTime.now()));
            } else {
                lrcCacheService.cacheMemberCredit(relationDO.getSubMemberId(), relationDO.getSubRoleId(), memberCreditDO.getCreditPoint(), memberCreditDO.getTradeCommentPoint(), memberCreditDO.getAfterSaleCommentPoint(), memberCreditDO.getComplainPoint(), memberCreditDO.getRegisterYearsPoint(), memberCreditDO.getAvgTradeCommentStar(), DateTimeUtil.diffYears(relationDO.getCreateTime(), LocalDateTime.now()));
            }

            //通知
            if(!plusPoint.equals(0)) {
                productFeignService.updateCommodityCreditScoreAsync(relationDO.getSubMemberId(), relationDO.getSubRoleId(), relationDO.getSubRole().getMemberType().getTypeEnum(), plusPoint);
            }

            Integer registerYears = DateTimeUtil.diffYears(relationDO.getCreateTime(), LocalDateTime.now());
            if(memberCreditDO.getTradeCommentCount().equals(0)) {
                templateFeignService.notifyCreditChangedAsync(relationDO.getSubMemberId(), relationDO.getSubRoleId(), relationDO.getSubMember().getName(), memberCreditDO.getCreditPoint(), registerYears, ServiceConfig.DEFAULT_TRADE_COMMENT_STAR);
            } else {
                templateFeignService.notifyCreditChangedAsync(relationDO.getSubMemberId(), relationDO.getSubRoleId(), relationDO.getSubMember().getName(), memberCreditDO.getCreditPoint(), registerYears, memberCreditDO.getAvgTradeCommentStar());
            }
        }

        return true;
    }

}
